package com.wh1200.mybatis

import com.wh1200.mybatis.xmlless.AnnotationSupport
import com.baomidou.mybatisplus.annotation.*
import com.baomidou.mybatisplus.core.handlers.AnnotationHandler
import com.wh1200.mybatis.xmlless.annotations.JsonMappingProperty
import com.wh1200.mybatis.xmlless.handler.JsonTypeHandler
import org.apache.ibatis.type.JdbcType
import org.apache.ibatis.type.UnknownTypeHandler
import java.lang.reflect.Field

/**
 *
 * @author 吴昊
 * @date 2023/12/19 14:07
 * @since v0.0.0
 * @version 1.0
 */
class XmllessAnnotationHandler : AnnotationHandler {

  override fun <T : Annotation?> getAnnotation(beanClass: Class<*>, annotationClass: Class<T>): T {
    if (annotationClass == TableName::class.java) {
      val table = AnnotationSupport.getCustomTableName(beanClass)
      val tableName = beanClass.getAnnotation(TableName::class.java)
      if (tableName == null && table != null) {
        @Suppress("UNCHECKED_CAST")
        return TableName(
            value = table.name,
            schema = table.schema ?: "",
            keepGlobalPrefix = false,
            resultMap = "",
            autoResultMap = false,
            excludeProperty = arrayOf()
        ) as T
      }
    }
    return super.getAnnotation(beanClass, annotationClass)
  }

  override fun <T : Annotation?> isAnnotationPresent(field: Field, annotationClass: Class<T>): Boolean {
    if (annotationClass == TableId::class.java) {
      return field.isAnnotationPresent(annotationClass) || AnnotationSupport.isIdField(field)
    }
    return field.isAnnotationPresent(annotationClass)
  }

  override fun <T : Annotation?> getAnnotation(field: Field, annotationClass: Class<T>): T {
    if (annotationClass == TableId::class.java) {
      val columnName = AnnotationSupport.getCustomColumnName(field)
      if (field.isAnnotationPresent(TableId::class.java)) {
        val tableId = field.getAnnotation(TableId::class.java)
        if (tableId.value.isBlank()) {
          @Suppress("UNCHECKED_CAST")
          return TableId(
              value = columnName ?: "",
              type = tableId.type
          ) as T
        }
      }
      val isKeyField = AnnotationSupport.isIdField(field)
      if (isKeyField) {
        @Suppress("UNCHECKED_CAST")
        return TableId(
            value = columnName ?: "",
            type = IdType.NONE
        ) as T
      }
    }
    if (annotationClass == TableField::class.java) {
      val tableField = field.getAnnotation(TableField::class.java)
      val customColumn = AnnotationSupport.getCustomColumnName(field)
      if (tableField != null) {
        @Suppress("UNCHECKED_CAST")
        return TableField(
            value = tableField.value.ifBlank { customColumn ?: "" },
            exist = tableField.exist,
            condition = tableField.condition,
            insertStrategy = tableField.insertStrategy,
            updateStrategy = tableField.updateStrategy,
            whereStrategy = tableField.whereStrategy,
            fill = tableField.fill,
            keepGlobalFormat = tableField.keepGlobalFormat,
            property = tableField.property,
            numericScale = tableField.numericScale,
            typeHandler = tableField.typeHandler,
            javaType = tableField.javaType,
            jdbcType = tableField.jdbcType,
            update = tableField.update,
            select = tableField.select
        ) as T
      }
      val typeHandler = if (field.isAnnotationPresent(JsonMappingProperty::class.java)) {
        JsonTypeHandler::class
      } else {
        UnknownTypeHandler::class
      }
      @Suppress("UNCHECKED_CAST")
      return TableField(
          value = customColumn ?: "",
          exist = true,
          condition = "",
          insertStrategy = when {
            AnnotationSupport.isInsertIgnore(field) -> FieldStrategy.NEVER
            else                                    -> FieldStrategy.DEFAULT
          },
          updateStrategy = when {
            AnnotationSupport.isUpdateIgnore(field) -> FieldStrategy.NEVER
            else                                    -> FieldStrategy.DEFAULT
          },
          whereStrategy = FieldStrategy.DEFAULT,
          fill = FieldFill.DEFAULT,
          keepGlobalFormat = false,
          property = "",
          numericScale = when {
            AnnotationSupport.getNumericScale(field) > 0 -> AnnotationSupport.getNumericScale(field).toString()
            else                                         -> ""
          },
          typeHandler = typeHandler,
          javaType = false,
          jdbcType = JdbcType.UNDEFINED,
          update = "",
          select = true
      ) as T
    }
    return field.getAnnotation(annotationClass)
  }

}
